<?php
/**
 *
 * @author Martin "DevelX" Jurča
 */
class AccessCounter extends Module {
    protected $name = 'AccessCounter';
    protected $administrable = true;
    protected $version = '2010-06-20';
    protected $details = array('dependencies' => array(),
            'observes' => array('AccessCounter'));

    const LOG = 'accessCounterLog';
    const REFERERS = 'accessCounter';
    const REFERERS_LOG = 'accessCountReferersStats';

    protected $logTable = array('time' => 'iNI', 'ip' => "v'15'IN");
    protected $refsTable = array('time' => 'iNI', 'referer' => "v'2048'",
            'count' => 'iNI');
    protected $refLogTable = array('date' => "v'8'NI", 'referer' => "v'2048'",
            'count' => 'iNI');

    protected $logRecord = array('table' => self::LOG, 'data' => array());
    protected $refRecord = array('table' => self::REFERERS, 'data' => array());

    public function __construct(DBAPI $dbapi, RecordList $recordList) {
        parent::__construct($dbapi, $recordList);
        $this->logRecord['properties'] = $this->logTable;
        $this->refRecord['properties'] = $this->refsTable;
    }

    public function install() {
        Modules::getModule('Users')->registerRights($this->getName(),
                $this->getRights());
        return $this->dbdriver->createTable(self::LOG, $this->logTable) &&
                $this->dbdriver->createTable(self::REFERERS, $this->refsTable)
                && $this->dbdriver->createTable(self::REFERERS_LOG,
                $this->refLogTable);
    }

    public function uninstall() {
        return $this->dbdriver->dropTable(self::LOG) &&
                $this->dbdriver->dropTable(self::REFERERS) &&
                $this->dbdriver->dropTable(self::REFERERS_LOG);
    }

    public function onReferersDetails(&$details, $source) {
        Kernel::setRedirect($this->getLink('referers-details/' .
                urlencode($details['from']) . '/' . urlencode($details['to']) .
                '/'));
    }

    public function  initDisplayBlank($param = null) {
        $this->countAccess();
        $referer = $this->countReferer();
        $this->updateRefererStats($referer);
    }

    public function displayAdminIndex() {
        $cols = array('COUNT(`ip`)');
        $today = &$this->dbdriver->select(self::LOG, $cols, '`time` >= ' .
                strtotime(date("d.m.Y")));
        $yesterday = &$this->dbdriver->select(self::LOG, $cols, '`time` < ' .
                strtotime(date("d.m.Y")) . ' AND `time` >= ' .
                (strtotime(date("d.m.Y")) - 86400));
        $week = &$this->dbdriver->select(self::LOG, $cols, '`time` >= ' .
                (time() - 604800));
        $month = &$this->dbdriver->select(self::LOG, $cols, '`time` >= ' .
                strtotime(date("1.m.Y")));
        $total = &$this->dbdriver->select(self::LOG, $cols);
        $cols = array('COUNT(`id`)');
        $users = &$this->dbdriver->select(Users::USERS_TABLE, $cols,
                '`active` > 0');
        $params = array('today' => $today[0]['COUNT(`ip`)'], 'yesterday' =>
                $yesterday[0]['COUNT(`ip`)'], 'week' =>
                $week[0]['COUNT(`ip`)'], 'total' =>
                $total[0]['COUNT(`ip`)'], 'month' => $month[0]['COUNT(`ip`)'],
                'users' => $users[0]['COUNT(`id`)']);
        $this->template('stats', $params);
    }

    public function displayAdminReferers() {
        $cols = array('count', 'referer');
        $orderBy = array('!count');
        $refs = &$this->dbdriver->select(self::REFERERS, $cols, '', $orderBy);
        $params = array('refs' => &$refs);
        $this->template('refs', $params);
    }

    public function displayAdminGraph() {
        $cols = array('MIN(`time`)');
        $start = &$this->dbdriver->select(self::LOG, $cols);
        $start = $start[0][$cols[0]];
        $stats = array();
        $cur = $start;
        $cols = array('COUNT(*)');
        while ($cur < time()) {
            $from = strtotime(date("Y-m-d 00:00:00", $cur));
            $month = (int) date("m", $cur) + 1;
            $year = (int) date("Y", $cur);
            if ($month > 12) {
                $month = 1;
                $year++;
            }
            $to = $from + 86400;
            $stat = &$this->dbdriver->select(self::LOG, $cols,
                    "`time` >= $from AND `time` < $to");
            $stats[] = array('time' => $from, 'stat' => $stat[0][$cols[0]]);
            $cur = $to;
        }
        $stats = array_reverse($stats);
        $params = array('stats' => &$stats);
        $this->template('graph', $params);
    }

    public function displayAdminSubmenu() {
        $menu = array(
            array('label' => 'accesses', 'href' => ''),
            array('label' => 'referers', 'href' => 'referers/'),
            array('label' => 'referersDetails', 'href' => 'referers-details/'),
            array('label' => 'graph', 'href' => 'graph/')
        );
        $this->prepareMenu($menu);
        $params = array('menu' => &$menu);
        $this->template('submenu', $params);
    }

    public function displayAdminReferersDetails($from = false, $to = false) {
        $from = $from ? $from : $this->getRefererDate(true);
        $to = $to ? $to : $this->getRefererDate(false);
        $form = array('start' => 'referersDetails', 'legend' => 'filtration',
                'submit' => 'view', 'items' => array(array('name' => 'from',
                'label' => 'from', 'value' => $from), array('name' => 'to',
                'label' => 'to', 'value' => $to)));
        $this->prepareFormData($form);
        $params = array('form' => &$form);
        $this->template('form', $params);

        $from = $this->dbdriver->escapeString($from);
        $to = $this->dbdriver->escapeString($to);
        $cols = array('DISTINCT `referer`');
        $referers = &$this->dbdriver->select(self::REFERERS_LOG, $cols,
                "`date` >= '$from' AND `date` <= '$to'");
        $cols = array('SUM(`count`)');
        foreach ($referers as &$referer) {
            $count = &$this->dbdriver->select(self::REFERERS_LOG, $cols,
                    "`date` >= '$from' AND `date` <= '$to' AND `referer` = '" .
                    $this->dbdriver->escapeString($referer['referer']) . "'");
            $referer['count'] = $count[0]['SUM(`count`)'];
        }
        $params = array('referers' => &$referers);
        $this->template('refdetails', $params);
    }

    private function getRefererDate($min) {
        $cols = array('date');
        $order = array($min ? 'date' : '!date');
        $date = &$this->dbdriver->select(self::REFERERS_LOG, $cols, '', $order,
                0, 1);
        return isset($date[0]) ? $date[0]['date'] : date("Ymd");
    }

    private function updateRefererStats($referer) {
        if (!$referer) {
            return;
        }
        $cols = array('count');
        $count = &$this->dbdriver->select(self::REFERERS_LOG, $cols,
                "`referer` = '" . $this->dbdriver->escapeString($referer) .
                "' AND `date` = '" . date('Ymd') . "'");
        if (isset($count[0])) {
            $update = array('count' => $count[0]['count'] + 1);
            $this->dbdriver->update(self::REFERERS_LOG, $update,
                    "`referer` = '" . $this->dbdriver->escapeString($referer) .
                    "' AND `date` = '" . date("Ymd") . "'");
            return;
        }
        $values = array('date' => date('Ymd'), 'referer' => $referer,
                'count' => 1);
        $this->dbdriver->insert(self::REFERERS_LOG, $values);
    }

    private function countReferer() {
        if (!isset($_SERVER['HTTP_REFERER']) ||
                (strpos($_SERVER['HTTP_REFERER'], Config::DOMAIN_NAME) !==
                false)) {
            return false;
        }
        $referer = strtolower($_SERVER['HTTP_REFERER']);
        $referer = preg_replace('/^http:\\/\\/(www[^.]*[.])?/', '', $referer);
        $referer = preg_replace('/\\/.*$/', '', $referer);
        $cols = array('count');
        $count = &$this->dbdriver->select(self::REFERERS, $cols,
                '`referer` = \'' . $this->dbdriver->escapeString($referer) .
                '\'');
        if (isset($count[0])) {
            $update = array('count' => $count[0]['count'] + 1);
            $this->dbdriver->update(self::REFERERS, $update, '`referer` = \'' .
                    $this->dbdriver->escapeString($referer) . '\'');
            return $referer;
        }
        $values = array('time' => time(), 'referer' => $referer, 'count' => 1);
        $this->dbdriver->insert(self::REFERERS, $values);
        return $referer;
    }

    private function countAccess() {
        $cols = array('ip');
        $check = &$this->dbdriver->select(self::LOG, $cols, '`ip` = \'' .
                $this->dbdriver->escapeString($_SERVER['REMOTE_ADDR']) .
                '\' AND `time` > ' . strtotime(date("d.m.Y")));
        if (!isset($check[0])) {
            $log = $this->logRecord;
            $log['data'] = array('ip' => $_SERVER['REMOTE_ADDR'], 'time' =>
                    time());
            $this->dbapi->save($log);;
        }
    }
}
?>
